package com.lession.config.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

@Component
@Aspect
public class LogAspect {
	private final static Logger logger = LoggerFactory.getLogger(LogAspect.class);
	
	@Pointcut(value = "execution(* com.lession.controller.*.* (..))")
	public void controllerPoint() {
	}
	
	@Pointcut(value = "execution(* com.lession.service.*.* (..))")
	public void servicePoint() {
	}
	
	@Before(value = "controllerPoint()")
	public void controllerBefore(JoinPoint jp) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		logger.info("{}  {}.{} : \t===== START ====="
				, "\t" + request.getRemoteAddr()
				, jp.getSignature().getDeclaringTypeName()
				, jp.getSignature().getName());
		logger.info("{}  {}.{} :  URL:{} METHOD:{}"
				, "\t" + request.getRemoteAddr()
				, "\t" + jp.getSignature().getDeclaringTypeName()
				, jp.getSignature().getName()
				, "\t" + request.getRequestURL().toString()
				, "\t" + request.getMethod()
		);
		logger.info("{}  {}.{} : \t===== END ====="
				, "\t" + request.getRemoteAddr()
				, "\t" + jp.getSignature().getDeclaringTypeName()
				, jp.getSignature().getName());
	}
	
	@AfterReturning(value = "controllerPoint()")
	public void controllerAfterReturning(JoinPoint joinPoint) {
		HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
		logger.info("{}  {}.{} :  URL:{} METHOD:{}"
				, "\t" + request.getRemoteAddr()
				, "\t" + joinPoint.getSignature().getDeclaringTypeName()
				, joinPoint.getSignature().getName()
				, "\t" + request.getRequestURL().toString()
				, "\t" + request.getMethod()
		);
	}
	
	@AfterThrowing(value = "servicePoint()", throwing = "e")
	public void serviceAfterThrowing(JoinPoint joinPoint, Throwable e) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		// 打印请求相关参数
		logger.error("{}  {}.{} : \t===== START ====="
				, "\t" + request.getRemoteAddr()
				, "\t" + joinPoint.getSignature().getDeclaringTypeName()
				, joinPoint.getSignature().getName());
		logger.error(e.getMessage(), e);
		logger.error("{}  {}.{} : \t===== END ====="
				, "\t" + request.getRemoteAddr()
				, "\t" + joinPoint.getSignature().getDeclaringTypeName()
				, joinPoint.getSignature().getName());
	}
	
	@Around("servicePoint()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		return pjp.proceed();
	}
	
}
